package com.demo.多线程;

/**
 * @Program: java
 * @ClassName ProducerConsumer
 * @Author: liutao
 * @Description: 生产者消费者模型：管程法
 * 生产者，消费者，缓冲区
 * @Create: 2023-10-27 13:20
 * @Version 1.0
 **/

public class ProducerConsumer {
    public static void main(String[] args) {
        SynchronizedContainer synchronizedContainer = new SynchronizedContainer();
        // 生产者线程
        new Producer(synchronizedContainer).start();
        // 消费者线程
        new Consumer(synchronizedContainer).start();
    }


}

/**
 * 生产者
 **/
class Producer extends Thread {
    SynchronizedContainer synchronizedContainer;

    public Producer(SynchronizedContainer synchronizedContainer) {
        this.synchronizedContainer = synchronizedContainer;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            Food food = new Food(i, "鸡腿饭");
            synchronizedContainer.push(food);
            System.out.println("Producer 生产 " + i + food.name);
        }
    }
}

/**
 * 消费者
 **/
class Consumer extends Thread {
    SynchronizedContainer synchronizedContainer;

    public Consumer(SynchronizedContainer synchronizedContainer) {
        this.synchronizedContainer = synchronizedContainer;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            Food food = synchronizedContainer.pop();
            System.out.println("Consumer 消费 " + food.id + food.name);
        }
    }
}

/**
 * 产品
 **/
class Food {
    int id;
    String name;

    public Food(int id, String name) {
        this.id = id;
        this.name = name;
    }
}

/**
 * 缓冲区
 **/
class SynchronizedContainer {
    /**
     * 装产品的容器
     **/
    Food[] foods = new Food[10];
    int count = 0;

    // todo：生产产品
    public synchronized void push(Food food) {
        if (count == foods.length) {
            // 通知消费者消费，生产等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        // 产品放入容器
        foods[count] = food;
        count++;
        // 通知消费者消费
        this.notifyAll();
    }

    // todo：消费产品
    public synchronized Food pop() {
        if (count == 0) {
            // 通知生产者生产，消费等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        // 消费
        count--;
        // 通知消费者消费
        this.notifyAll();
        return foods[count];

    }
}
